\section{简介}

站在笔记撰写的 21 世纪 20 年代，人工智能 (Artificial Intelligence, AI) 无疑是一个非常热门的领域，也被认为是实现第四次工业革命的核心科技。人工智能技术意图让计算机去做过去只有人才能作的智能工作，其目标是能在所有方面的工作上达到或者超过人类的水平。目前，人工智能已经在语音、图像、视频、文字等模态的理解和生成上取得了巨大成就。

我们前面介绍过机器学习以及一些统计学习方法，而深度学习是机器学习中的一种，并且是直到今天最为成功的一种。它的最初动机是建立模仿人脑的结构来解释数据，如图像、文本等等。而如今依靠极大规模参数的模型以及数据，某些对话模型已经被认为涌现出了人类智能，甚至在某种程度上通过了图灵测试。

深度学习模型的基础，始于 1943 年 McCulloch 和 Pitts 的神经元模型，后来 1958 年，由 Rosenblatt 等人提出了感知机模型，这在之前的一章已经介绍过，感知机模型无法实现异或运算的特性也使得神经网络领域经历了数十年的停滞。1986 年，由 Rumelhart 和 Hinton 等人提出了反向传播算法，以及 1998 年的 LeCun 等人提出了卷积神经网络 (Convolutional Neural Network, CNN)，逐步奠定了现代神经网络的基础。2006 年，Hinton 等人首次提出了深度学习的概念，并且指出可以通过逐层初始化解决神经网络训练过程中的梯度消失问题。

神经网络最近一次引起广泛关注，起始于 2012 年的 ImageNet 图像识别挑战赛。在比赛中，Alex Krizhevsky, Ilya Sutskever 和 Geoffrey Hinton 等人提出的 AlexNet 深度卷积神经网络一举夺冠，并且获得了碾压第二名基于支持向量机模型的效果。2016 年，使用深度强化学习训练的 AlphaGo 击败了人类围棋冠军，并成为世界围棋冠军。2020 年，OpenAI 公司发布了 GPT-3 模型，其拥有 1750 亿个参数。前所未有的复杂性使得 GPT-3 模型实现了深层次的语言理解和生成，并最终支撑了 ChatGPT 模型能与人类进行多轮对话 (从而可以被认为通过图灵测试)。

关于深度学习为什么能工作，理论众说纷纭，但尚未有人能给出明确的答案。对此，我们摘抄两篇著名的文章，以进行一个整体的把握。

第一篇文章是凝聚态物理学家、诺贝尔奖得主 Philip Anderson 在 1972 年发表的文章，题为《多者异也》。在其中，Anderson 指出：
\begin{quotation}
    \it
    还原论（reductionist）假说在哲学家中或许仍具争议，但我认为，该假说无疑已被绝大多数活跃的科学家所接受了。我们的思维和身体的运作，以及我们所知的任何有生命的或无生命的物质的运作，被认为是被相同的一套基本定律所控制的。除了在某些极端情况下基本定律可能失效，我们已经非常了解这些基本定律。

    以下结论似乎是还原论的显然推论：如果万事万物遵循相同的基本定律，那么只有研究真正基础的事物的科学家才是研究基本定律的人，也就是指某些天体物理学家、粒子物理学家、逻辑学家、数学家以及极少数的其他学科的科学家。
    
    ……

    这种想法的主要谬误在于还原论假说从来都不意味着“建构论（constructionist）”假说：将所有事物还原为简单的基本定律的能力并不意味着从那些基本定律出发并重建整个宇宙的能力。事实上，粒子物理学家告诉我们越多关于基本定律的本质，这些基本定律和其他学科的问题的关联越少，和社会问题的关联也越少。

    在面对尺度（Scale）和复杂性（Complexity）的孪生难题时，建构论假说轰然瓦解。事实证明，我们无法根据少数粒子的性质的简单外推，来理解大量且复杂的基本粒子集合体的行为。相反的，在任何不同的复杂性层级下，物质会出现全新的性质。并且，对新性质的理解需要本质上一样的基础研究。

    ……

    基于层层推测，我觉得下一个阶段是功能的层级结构或专门化，或者同时包括两者。某种意义上，我们应该停止讨论降低的对称性，而将其称为增加的复杂性。因此，随着每个层级的复杂性不断增加，我们沿着学科的层级结构上升。在将复杂性较低的部分组合为更复杂的系统、并理解由此导致的新性质的过程中，我们在每个层级都会遇到迷人的且基础的问题。

    ……

    粒子物理学家的自大和他的内涵性研究可能已经被我们抛在身后（正电子的发现者曾称“剩下的都是化学”），但是我们仍然没有从一些分子生物学家的自大中恢复过来，这些生物学家似乎坚定地尝试将人类有机体的所有事物还原为“仅仅是”化学，范围从普通的感冒和所有的精神疾病到宗教本能（religious instinct）。显然，人类行为学和 DNA 之间的组织层次比 DNA 和量子电动力学之间更多，并且每个层级都需要全新的概念结构。

    最后，我想借用两个经济学的例子。马克思曾说量变导致质变，但是1920 年代巴黎的一段对话将该观点概括地更加清楚：

    菲茨杰拉德：富人和我们不同。

    海明威：是的，他们有更多的钱。
    
\end{quotation}

我们在笔记中曾经介绍过统计物理学的内容。的确，整个概率论和数理统计学科，都在尝试处理极大数目所呈现出来的规律。如今，大型模型，所带来的 Scale up 定律以及涌现出来的智能，或许在计算机模拟的层面中又一次照应了这篇文章提出的观点。

另一篇文章是强化学习之父 Rich Sutton 撰写的文章，题为《苦涩的教训》。Sutton 回顾了人工智能过去在国际象棋、围棋、语音识别、计算机视觉等领域的发展历史。他发现，过去人们在算力受限的情形下，往往会为了达到更好的效果，运用自己的知识来干预模型的结构。然而，最终这些方法都败给了强大算力加持下的通用方法。更可悲的是，由于人们往往沉溺于用小模型结合自己的知识来获得相对较好的效果，使得真正能利用好算力的大型模型很难被发现——从而阻碍了 AI 在这些领域的进展。

因而，这是一个苦涩的教训：

\begin{quotation}
    \it
    这是一个重要的教训。作为一个领域，我们还没有完全吸取这一教训，仍在重蹈覆辙。为了识别并避免这种错误，我们必须理解其吸引力所在。我们必须领悟到，试图构建一个基于我们认为自己思考方式的系统是行不通的。苦涩的教训源于这样的历史观察：
    \begin{enumerate}
        \item 人工智能研究者经常试图将知识融入他们的代理中；
        \item 这在短期内总是有益的，也让研究者感到满足；但 
        \item 从长远来看，这种做法会导致进步停滞，甚至阻碍进一步的发展；
        \item 真正的突破性进展最终是通过一个相反的方法实现的，这个方法基于通过搜索和学习来扩大计算的规模。
    \end{enumerate}
    这种成功带有苦涩，往往消化不良，因为它是在人类中心化方法之上取得的。

    从这个苦涩的教训中，我们应该明白通用方法的巨大力量，即那些随着计算能力的增长而持续扩展的方法。在这方面，似乎可以无限扩展的两种方法是搜索和学习。

    苦涩教训中的另一个关键点是，人类心灵的实质内容极其复杂，不可能简化；我们应该放弃试图简单化地理解心灵内容，如空间、物体、多重代理或对称性等概念。这些都是外部世界中任意而复杂的部分，不应该成为我们构建的核心；相反，我们应该构建的是那些能够发现并捕捉这种任意复杂性的元方法。这些方法的核心在于它们能够找到良好的近似，但寻找这些近似的过程应该由我们的方法来完成，而不是我们亲自动手。我们希望 AI 代理能像我们一样具有发现能力，而不是仅仅包含我们已有的发现。将我们的发现直接构建进去，只会使我们更难看清如何实现发现的过程。
    
\end{quotation}

根据 Sutton 的观点，那些最有用的模型，就是能最大程度利用计算力的模型。为什么最大程度利用算力，就能获得最好的效果？或许正是因为，多者异也。


\section{多层感知机}

多层感知机 (Multilayer Perceptron, MLP)，也叫做前馈神经网络，是最基本的神经网络。它的目标是近似某个函数 $f^*$。例如，对于分类器，$y=f^*(\vec{x})$ 将输入 $\vec{x}$ 映射到某一个类别 $y$。前馈网络定义了一个映射 $\vec{y}=f(\vec{x};\vec{\theta})$，通过学习参数$\vec{\theta}$的值，使得它能够获得最佳的函数近似。这种模型被称为前向的 (feedforward)，是因为信息流过 $\vec{x}$ 的函数，流经用于定义 $f$ 的中间计算过程，最终达到输出 $\vec{y}$。在模型的输出和模型本身之间没有反馈(feedback)连接。当前馈神经网络被扩展成包含反馈连接时，则被称为循环神经网络，后面会介绍。

我们在这一节中，充分利用在前面几章所讲的方法，包括准备数据、优化方法、正则化方法，来走完典型的深度学习流程。

之所以这种模型被称为网络，是因为它往往可以由许多函数复合而成。例如，我们可以给出 $f(\vec{x}) = f_3(f_2(f_1(\vec{x})))$。这些链式的结构是神经网络中最常用的结构，其中 $f_1$ 被称为第一层，$f_2$ 被称为第二层，最后一层则被称为输出层。一般而言，标签只会给出 $y\approx f^*(\vec{x})$ 的值，而不是其中每一层的值，所以这些非输出层被称为隐藏层。链的全长被称为深度，也是深度神经网络名词的来源。既然深度神经网络是复合函数，所以当我们希望使用优化方法，从数据中逼近我们想要的结果时，我们可以使用反向传播方法来处理。事实上，随机梯度下降法正是深度学习中广泛应用的基础方法，而反向传播则给出了计算任意规模复合函数的梯度的方法。

\paragraph{多层感知机学习异或问题}
考虑学习异或的问题。这个问题是单层感知机解决不了的，曾导致神经网络方法数十年的停滞。现在通过加深深度，我们可以实现这一点。我们的目标是，给定 $\vec{x}=(x_1, x_2)$，当 $x_1$ 和 $x_2$ 中恰好有一个是 1，另一个是 0 时，返回 1，而其他时候返回 0。$x_1$ 和 $x_2$ 的取值也只能是 0 和 1。此时，损失函数是 
\begin{equation}
    J(\theta) = \frac{1}{4}\sum_{x\in\mathbb{X}}(f^*(\vec{x}) - f(\vec{x}; \theta))^2
\end{equation}
我们这里选用均方误差作为损失函数。然后，我们就要选择模型的形式。线性模型难堪大任，因此我们必须引入非线性。大多数多层感知机在线性变换后，都会跟着一个激活函数，这个激活函数是非线性的：
\begin{equation}
    \vec{h} = g(W^T\vec{x} + \vec{c})
\end{equation}
其中 $W$ 是线性的权重，$\vec{c}$ 是偏置项，也是模型参数的一部分。而 $g(z)$ 就是激活函数。一般来说，可以选择这些激活函数，比如 
\begin{enumerate}
    \item 线性整流单元 (Rectified Linear Unit, ReLU), 即 $g(z) = \max\{0,z\}$
    \item 双曲正切函数，即 $g(z) = \tanh(z)$
    \item Sigmoid 函数，也叫逻辑斯蒂函数，即 $g(z) = 1/(1+e^{-z})$
\end{enumerate}
现在我们使用 ReLU 来作为激活函数，这是默认推荐的选择。总的来说，我们给出两层网络：
\begin{equation}
    f(\vec{x}; w_1, c_1, w_2, c_2) = w_2\max{0, w_1\vec{x} + c_1} + c_2
\end{equation}
最后，我们指出，
\begin{equation}
    w_1 = \begin{pmatrix}
        1&1\\
        1&1
    \end{pmatrix},\quad c_1 = \begin{pmatrix}
        0\\-1
    \end{pmatrix},\quad w_2 = \begin{pmatrix}
        1\\-2
    \end{pmatrix},\quad c_2 = 0
\end{equation}
是问题的解。

\paragraph{学习目标与优化}
不过上面的例子没有涉及到优化过程。事实上，面对数万甚至数万亿的样本，数百万甚至数十亿的参数，只能优化。而优化就涉及到了计算梯度，复合函数的梯度计算那自然就是误差逆传播算法。我们已经在前两章中详细讲过。

\begin{figure}[H]
    \includegraphics[width=0.6\linewidth]{figure/BP.png}
    \centering
    \caption{误差逆传播算法}
\end{figure}

有了神经网络，该如何处理输出？或者说，我们学习的目标是什么？在机器学习基础一章中，我们已经讲过设计目标函数的方法，并且介绍了均方误差最小、极大似然估计、和最大后验估计之类的方法。

在大多数情况下，我们的参数模型定义了一个分布 $p(\vec{y}|\vec{x};\theta)$并且简单地使用极大似然估计。这就意味着，我们使用训练数据和模型预测之间的交叉熵作为代价函数。有时，我们使用一个更简单的办法，不是预测 $\vec{y}$ 的完整概率分布，而是仅仅预测在给定 $\vec{x}$ 的条件下 $\vec{y}$ 的某种统计量。极大似然估计所给出的代价函数我们已经在机器学习基础一章中介绍过，这里用一些稍微不同的符号来表示：
\begin{equation}
    J(\theta) = -E_{\vec{x}, \vec{y}\sim\hat{p}_{data}}\log p_{model}(\vec{y}|\vec{x})
\end{equation}
如果模型的分布 $p_{model}(\vec{y}|\vec{x})=N(\vec{y}; f(\vec{x};\theta), I)$ 是正态分布，那么和我们当时对线性模型所作的一样，我们会得到均方误差代价：
\begin{equation}
    J(\theta) = \frac{1}{2}E_{\vec{x}, \vec{y}\sim\hat{p}_{data}} \| y-f(\vec{x};\theta)\|^2
\end{equation}
使用极大似然估计的好处是，它减轻了为每个模型设计不同代价函数的负担。只要你给定了模型分布，你就自动得到了代价函数 $\log p(\vec{y}|\vec{x})$。尤其是，如果我们认为模型分布是正态分布，那我们就可以直接使用均方误差最小的策略。

有时，我们并不想学习完整的概率分布，而只是想学习在给定 $\vec{x}$ 时 $\vec{y}$ 的某个条件统计量。比如说，我们可能有个预测器 $f(\vec{x};\theta)$，想用它来预测 $\vec{y}$ 的均值。如果我们使用一个足够强大的神经网络，那么这个神经网络可以认为是一个泛函了，我们实际上就可以选择一个函数，而不仅仅是选择一组参数。使用泛函的思想，解决问题就到了变分法。其结果为：
\begin{equation}
    f^* = \arg\min_{f} E_{\vec{x}, \vec{y}\sim\hat{p}_{data}}\|\vec{y}-f(\vec{x})\|^2
\end{equation}
得到 
\begin{equation}
    f^*(\vec{x}) = E_{\vec{y}\sim p_{data}(\vec{y|\vec{x}})}\vec{y}
\end{equation}
这一步来自于我们曾讲过的条件数学期望。我们曾在随机变量的最佳预测中提到过，在所有用 $Y$ 的函数对 $X$ 进行预测中，条件数学期望 $E(X|Y)$ 在均方差的意义下是最优的。

换句话说，如果我们能用无穷多的、来源于真实的数据生成分布的样本进行训练，最小化均方误差代价函数将得到一个函数，它可以用来对每个 $\vec{x}$ 值预测一个 $\vec{y}$ 值。

不同的代价函数给出不同的统计量。第二个使用变分法的结果是 
\begin{equation}
    f^* = \arg\min_{f} E_{\vec{x},\vec{y}\sim p_{data}}\|\vec{y} - f(\vec{x})\|_1
\end{equation}
这种做法得到的是对每个 $\vec{x}$ 预测 $\vec{y}$ 取值的中位数。这个代价函数叫做平均绝对误差(Mean Absolute Error, MAE)。

然而，不论是 MSE 还是 MAE，在基于梯度的优化方法上往往成效不佳，因为饱和的输出单元结合这些代价函数可能产生相当小的梯度，使得更新缓慢。所以交叉熵代价还是要更受欢迎一些，毕竟在接近 0 时，对数函数是趋于无穷大的。

\paragraph{输出单元}
代价函数的选择，和输出单元紧密相关。大多数时候，我们简单地使用数据分布和模型分布之间的交叉熵。选择如何表示输出决定了交叉熵函数的形式。任何可以用来表示输出的神经网络单元，原则上也可以用来表示隐藏单元。我们假设网络提供了一组定义为 $\vec{h} = f(\vec{x};\theta)$ 的隐藏特征。输出层的作用就是随后对这些特征进行一些额外的变换，来完成整个网络必须完成的任务。

一种简单的输出单元是基于仿射变换的输出单元。仿射变换不具有非线性，所以它们一般被称为线性单元。它一般用来产生条件高斯分布的均值：
\begin{equation}
    p(\vec{y}|\vec{x}) = N(\vec{y};\hat{\vec{y}}, I)
\end{equation}
最大化其似然对数，等价于最小化均方误差。然而，对于所有的输入，协方差矩阵都必须被限定成一个正定阵。线性输出层难以满足这个设定，所以会有一些其他的输出单元来对协方差参数化。

Sigmoid 输出单元可以用来给出 Bernoilli 分布。许多任务需要预测二值型变量 $y$ 的值。具有两个类的分类问题可以归结为这种形式。此时，最大似然的方法，是定义 $y$ 在 $\vec{x}$ 条件下的 Bernoulli 分布，神经网络则只需要预测 $P(y=1|\vec{x})$ 即可。为了使得这个数是有效的概率，它必须处于区间 $[0, 1]$ 之中。如果我们想要使用线性单元来作为输出，并且用阈值来控制它的值处在0到1的范围，那么我们可能会面临梯度消失的问题。sigmoid 函数就不会有这个问题，它肯定在 $[0,1]$ 的区间内，并且梯度永不为零。一般，用于定义这种二值型变量分布的变量$z$ 称为分对数 (logit)。

Softmax 单元可以用来输出 Multinoulli 分布。如果我们想要一个具有 $n$ 个取值的离散型随机变量的分布时，就可以使用 softmax 函数，它可以看作是 sigmoid 函数的扩展。它常用于分类器的输出，用来表示 $n$ 个不同类上的概率分布。对于向量 $\hat{\vec{y}}$ 而言，它的每个元素是 $\hat{y}_i = P(y=i|\vec{x})$。我们不仅要求每个 $\hat{y}_i$ 元素介于 0 和 1 之间，还要使得整个向量的和为 1，使得它表示一个有效的概率分布(严格来说，作为离散变量，是分布列)。那么，我们通过线性层可以预测没有归一化的对数概率：
\begin{equation}
    \vec{z} = W\vec{h} + \vec{b}
\end{equation}
其中 $z_i = \log \hat{P}(y=i|\vec{x})$，$\hat{P}$是相对的概率大小，但没有归一化。那我们怎么归一化呢？可以使用 softmax 函数，首先把 $z_i$ 通过指数函数都映射为大于零的值，然后再除以这些值的和：
\begin{equation}
    \text{softmax}(\vec{z})_i = \frac{\exp(z_i)}{\sum_j \exp(z_j)}
\end{equation}
有趣的是，在笔记的经典统计物理一章中，我们曾经用能量作为 $-z$，而把能量的 softmax 函数的分母叫做配分函数。在这里我们就可以将粒子的能量取值概率，与这里的多个分类输出概率相对应。

此外，对于一些采样过程，我们还可以定义温度$T$，它起到的作用也是在指数 $z_i$ 前面加一个系数$1/T$。从而 
\begin{equation}
    \text{softmax}(\vec{z}) = \frac{\exp(z_i/T)}{\sum_j \exp(z_j/T)}
\end{equation}
这样，在接近零度下，softmax 函数产生的结果，便是具有最大 $z$ 的概率为 1，而其他值的概率为 0，采样一定会给出确定性的结果；而在很高的温度下，$z_i$ 的指数全都趋于 1 了，因而采样会给出比较均一的结果。这里的温度在形式上也和我们在经典统计物理中引入的类似。


\paragraph{架构设计}

神经网络设计的另一个关键点在于架构，也就是网络应该有多少个单元，以及这些单元应该如何连接。大多数神经网络被组织称为层 (layer) 的单元组，而这些层被布置为链式结构，后一层是前一层的函数。在这些链式架构中，主要的架构考虑就是选择网络的深度和每一层的宽度。经验表明，即使只有一个隐藏层的网络也足够能适应训练集(万能近似定理)，但更深的网络往往能使用更少的参数来进行复杂模式的表征。

然而，尽管万能近似定理能保证一定存在单隐藏层的函数能拟合数据集，但并不能保证我们一定能训练得到这样的函数。而且，理论预言所需的参数量可能大得离谱。所以，这个定理只能给我们对多层感知机的能力提供一些信心，而不能用来实际指导训练。

% \paragraph{正则化方法} 

% 我们在机器学习基础一章中讲了一些正则化方法，但还有一些适合于 MLP 及其衍生的模型的正则化方法，比如 Dropout。Dropout 的方法，是从基础网络中，除去一些非输出单元之后，形成子网络。

% 我们定义 $k$ 个不同的模型，从训练集有放回地采样构造 $k$ 个不同的数据集，然后在训练集 $i$ 上训练模型 $i$。Dropout 的目标是在指数级数量的神经网络上，近似这个过程。具体来说，在训练中使用 Dropout 时，会使用基于小批量产生较小步长的学习算法，比如随机梯度下降。我们每次在小批量中加载一个样本，然后随机抽样应用于网络中所有输入和隐藏单元的不同二值掩码 (Mask)。对于每个单元，掩码是独立采样的，并且掩码值为 1 的概率是训练前固定好的超参数，一般对于输入单元取 0.8，隐藏单元取 0.5。然后，运行和之前一样的前向传播、反向传播和更新。

% 这样做，实际上会在每一个小批量中，产生一个子网络，它删除掉了一些节点，然后对剩余节点进行推理、反向传播、更新。



\section{卷积神经网络}

卷积网络 (Convolutional Neural Network, CNN) 是一种专门用来处理具有类似网格结构的数据的神经网络。一般而言，卷积是对两个实函数的运算。假设我们用激光传感器追踪宇宙飞船的位置。激光传感器给出的是单独的输出$x(t)$，表示宇宙飞船在时刻$t$的位置。现在，激光传感器受到一定的噪声干扰，所以我们希望将测量结果进行一定的加权平均。显然，时间上越近的测量结果越相关，所以这里的权重更高。我们用 $w(a)$ 来表示权重，其中$a$表示测量结果距离当前时刻的时间间隔。我们对任何时刻$t$都采用这种加权平均的操作，就得到了一个新的对飞船位置的平滑估计函数$s(t)$：
\begin{equation}
    s(t) = (x*w)(t) = \int x(a) w(t-a)\dd{a}
\end{equation}
其中，第一个参数(函数$x(t)$)是输入，第二个参数(函数$w(t)$)是核函数。$*$就是卷积运算。输出有时候被称为特征映射。

在机器学习的应用中，输入通常是多维数组的数据，而核通常是由学习算法优化得到的多维数组的参数。尽管和数学/物理中定义的张量毫无关系，但这里仍把这些多维数组叫做张量。我们也经常在多个维度上进行卷积运算。例如，把二维的图像作为输入，那么就会使用一个二维的核：
\begin{equation}
    S(i,j)=(I*K)(i,j)=\sum_m \sum_n I(m, n) K(i-m, j-n)
\end{equation}
卷积运算是可以交换的，所以 
\begin{equation}
    S(i,j) = (K*I)(i,j) = \sum_m \sum_n I(i-m, j-n) K(m,n)
\end{equation}
卷积运算可交换性来源于，我们将核相对于输入进行了翻转。随着求和的进行，$m$ 在增大，但 $i-m$ 却在减小。翻转核的唯一目的是实现可交换性。在实际的代码中，常常会实现互相关：
\begin{equation}
    S(i,j) = (I*K)(i,j) = \sum_m \sum_n I(i+m, j+n) K(m,n)
\end{equation}
核卷积运算几乎一样，但不翻转。有许多机器学习的库实现的是互相关函数，但却把它叫做卷积。卷积是一种线性变换，这意味着它等价于矩阵乘法，而且这些矩阵通常都非常稀疏。

\paragraph{动机} 在多层感知机中引入卷积神经网络的动机有三个：稀疏交互、参数共享以及等变表示。
\begin{enumerate}
    \item 稀疏交互：卷积运算的稀疏性，使得神经网络中的参数数量远少于多层感知机。传统的神经网络使用矩阵乘法来建立输入和输出的连接关系，其中参数矩阵中的每一个参数都描述了一个输入单元和一个输出单元间的交互。但在CNN中，核的大小远小于输入的大小，因此输出的值只来自于它附近的、只与核进行了运算的那些输入。
    \item 参数共享则指的是一个模型中的多个函数中使用相同的参数。在传统的神经网络中，当计算一层输出时，权重矩阵的每一个元素只使用一次，当它乘以一个输入的元素后就再也不会用到了。但在CNN中，所有输出值，其都是由它附近的输入，乘以相同的(共享的)核函数，再相加得来。这一点没有改变前向传播的计算时间，但大大减少了参数数量。
    \item 等变表示：神经网络层对平移是等变的。事实上，一般的卷积也是具有平移不变性的。这意味着，如果我们将输入函数进行平移再进行卷积，那么所得的结果，和先进行卷积再进行平移的结果是一样的。当处理时间序列数据时，这意味着可以通过卷积得到输入中出现不同特征的时刻所组成的时间轴。当我们把输入的一个事件向后延时，那么输出的相应位置也会向后延时。对于二维的图像输入也有类似的效应。不过，卷积对其他类型的变换不是等变的，比如图像缩放、旋转等，需要一些其他的机制来处理。
\end{enumerate}

\paragraph{三级结构: 卷积、激活与池化} 在卷积网络中，一个典型的层 (layer) 包含三级。在第一级中，这一层并行地计算多个卷积产生的一组线性激活响应。在第二级中，每一个线性激活响应会通过一个非线性的激活函数，如 ReLU。在第三级中，使用池化函数 (pooling function) 来进一步调整这一层的输出。当然，也有的术语把这三级称为卷积层、激活层和池化层。这里我们不这么叫。

池化函数，就是使用某一位置的相邻输出的总体统计特征，来代替网络在该位置的输出。比如，最大池化 (max pooling) 就给出了相邻矩形区域内的最大值。其他常用的池化函数包括相邻矩形区域内的平均值、$L^2$ 范数以及基于与中心像素距离的加权平均函数。不管采用什么池化策略，当输入作出少量平移时，池化都能帮助输入的表示近似不变。使用池化可以看作是增加了一个无限强的先验，也就是说这一层的函数必须具备对少量平移的平移不变性。这不禁让人想起诺特定理中的、针对无穷小平移的平移不变性。在诺特定理中，每一种无穷小平移的不变性，都对应了一个守恒量。在卷积网络的结构设计中，或许也是为了强迫模型找到某种不变量，而这种不变量正是图像最显著的特征吧。

\paragraph{卷积的通道数和步长} 在神经网络中，所谈论的卷积，一般都和标准的离散卷积运算有一点区别。例如对于图像处理来说，输入往往是三个矩阵 (RGB) 而不是一个。在实际训练的时候，一次可能计算一批而不是一张图像，因此训练所用的输入是四维张量。而卷积核也不单单只是一个二维矩阵，而是一个三维张量，因为每个二维卷积核都只能提取一个特征，而我们往往需要多个特征才能共同决定一个图像的类别。

有时候，我们还会希望跳过核中的一些位置来降低计算的开销 (相应的代价是提取的特征没有先前那么好了)。我们可以把这一过程看作是对全卷积函数输出的下采样。如果我们只想在输出的每个方向上，每间隔$s$个像素进行采样，那么可以定义一个下采样卷积函数 $c$ 使得 

\begin{equation}
Z_{ijk}=c(K,V,s)_{ijk}=\sum_{lmn}V_{l,(j-1)s+m, (k-1)s+n}K_{ilmn}
\end{equation}

其中$K$是卷积核，$V$是层的输入，$Z$是层的输出。我们把 $s$ 称为下采样卷积的步幅 (stride)。步幅大于一个像素的卷积，等价于步幅为一个像素的标准卷积+降采样。

\paragraph{卷积核的反向传播} 在训练卷积神经网络时，必须在给定输出的梯度时能计算核的梯度。由于卷积是一种线性运算，因此当我们把输入以及输出都展平为向量时，卷积就会变成一个稀疏的矩阵，并且这个矩阵中有相当多的重复单元。这些重复单元都会对结果有所贡献，因而它们的变化量由所有重复单元计算得来的梯度的和 (而不是平均值) 来决定。

\paragraph{残差连接}

\section{卷积神经网络的应用 (计算机视觉)}

既然卷积神经网络被提出时便是模仿人类的视觉神经机制的，那么显然它最适合于计算机视觉的应用。

\paragraph{图像分类} 

\paragraph{目标检测} 目标检测是计算机视觉中的一个重要任务，它不仅需要识别图像中的物体类别，还要确定每个物体的位置（即在图像中的边界框）。相比于图像分类，目标检测的任务更复杂，因为它要求模型同时输出类别和位置。

在目标检测中，通常使用边界框 (bounding box) 来描述对象的空间位置。边界框是矩形的，由矩形左上角的以及右下角的坐标决定。另一种常用的边界框表示方法是边界框中心的坐标以及框的宽高。

目标检测算法通常会在输入图像中采样大量的区域，然后判断这些区域中是否包含我们感兴趣的目标，并调整区域边界从而更准确地预测目标的真实边界框。不同模型所采用的区域采样方法可能不同，一种简单的办法是，以每个像素为中心，生成多个缩放比和宽高比不同的边界框，称为锚框 (anchor box)。给定中心位置 (每隔一定的像素数，一般由特征图的尺寸决定)，设置锚框不同的宽高比和缩放比，生成大量的锚框。

如果某个锚框能比较好地覆盖了图像中的目标，那么它与真实边界框之间的交并比应该会较高。交并比定义为 $IOU = \frac{A_1 \cap A_2}{A_1 + A_2 - A_1 \cap A_2}$，其中 $A_1$ 和 $A_2$ 分别是两个区域面积。交并比的范围在0和1之间，0表示边界框没有重合像素，而1表示边界框完全重合。

那么神经网络输出什么呢？神经网络接受图像作为输入，其输出则是具有一定尺寸和通道数的特征图。特征图中的每一个像素都对应于具有特定中心位置的锚框，而不同的通道则蕴含不同的涵义。我们举个例子：
\begin{enumerate}
    \item 假设输入图像是 $300\times 300$ 的图像。
    \item 我们预先设定好，经过一系列的卷积、池化，神经网络末尾的特征图的尺寸被缩小到 $38 \times 38$。
    \item 由于每个神经网络的特征图像素都有一定的感受野，掌管了一定大小的区域。所以我们把图像分割成 $38\times 38$ 份，每份大概是 $8\times 8$ 个像素。
    \item 每份的中心位置就是锚框的中心位置。我们可以根据预先设定好的策略，划定一系列具有不同宽高比和缩放比的锚框。例如，我们这里可以选 3 个宽高比，再选 3 个缩放比，生成 9 个锚框。
    \item 对于每个锚框，都有对应的类别 (假设总共有 $C$ 个类别，那么每个类别都会有一个概率)，以及针对特定类别的偏移量 (4个参数，分别是中心点的$dx$, $dy$ 以及尺寸的$dw$, $dh$)。
    \item 因此，神经网络的输出张量便是 $38\times 38\times 9\times (C + 4)$。针对训练集中的每张图像及其真实框，都可以计算出这个张量。将它和神经网络的输出进行比对，用以训练。
    \item 对于那些和真实边框不太相关的锚框 (这很常见)，通常不将它们计入损失。这可以通过设置掩码矩阵来实现，将掩码矩阵作用于损失函数，这样被忽略的锚框对应的位置，对损失就没有贡献了。
\end{enumerate}

需要注意的是，神经网络输出张量的各个通道的意义不同。其中，$C$ 表示类别，应该经过 softmax 处理得到概率分布，然后与真实值的交叉熵作为损失。而 $4$ 表示偏移位置，可以用常见的回归损失 (比如 Smooth L1 Loss)。对于总损失，则应该视为这两者的加权和。

训练好后，我们需要将神经网络预测的结果转换为边界框。每次，神经网络都会预测 $9\times 38\times 38$ 个锚框 (我们只取最有可能的那个类别所对应的锚框)。但这还是太多了，需要缩减。策略如下：
\begin{enumerate}
\item 对每个锚框，取其类别预测中最高的概率作为置信度。如果概率最高也不过 0.5，就丢弃这个锚框。
\item 非极大值抑制。对于剩下的预测框，我们仍取置信度最高的锚框。剩下的框也按照置信度排序，然后一一检测其与置信度最高锚框之间的交并比。如果交并比超过一定的值，就认为这个锚框已经有了 (被置信度最高的锚框检测到了)，所以就没必要留下。重复这个过程，直到没有剩余的锚框。
\end{enumerate}

这样，剩下的预测框就是最终的检测结果，包括类别和边界框。

目标检测有几种流行的框架。首先是 Faster R-CNN。它由两个部分组成，第一个是 RPN (Region Proposal Network)，第二个是 Fast R-CNN。其中，RPN 和我们上面描述的输入图片、输出包含 $9\times (C+4)\times 38\times 38$ 的特征图的那个神经网络是一样的。而 Fast R-CNN 部分，则对这个特征图进行进一步处理。



\section{循环神经网络}

除了认识图像外，人工智能的另一个基础目标便是认识文本。或者，换句话说，认识那些具有一定顺序性的数据，这就是序列建模。循环神经网络 (Recurrence Neural Network, RNN) 是解决序列问题的一个重要模型。

\paragraph{自然语言建模方式} 循环神经网络所面临的基本问题可以这样建模：输入一个向量序列$\fbk{\vec{x}_t}_{t=1}^{T}$，然后输出对应的一个序列$\fbk{\vec{y}_t}_{t=1}^{T}$。其中，$x_i, y_i\in\mathbb{R}^d$。需要注意的是，这里的每个向量，都和前后的向量有一定的因果关系。对于文本而言，这实际上也是个分类的过程，也就是说，在序列中的每一个元素，需要预测的是所有类别(输出哪个字)的概率分布。

在自然语言处理中，主要有两种编码方式：

\begin{enumerate}
    \item One-hot 编码：这是最简单的编码方式。假设词汇表大小为$V$，那么每个词都会被表示为一个$V$维的向量，其中只有对应词索引的位置为1，其他位置都为0。例如，对于词汇表["猫", "狗", "鸟"]，"猫"可以表示为$[1,0,0]$，"狗"表示为$[0,1,0]$。这种编码方式简单直观，但存在维度灾难问题，且无法表达词语之间的语义关系。

    \item Word2Vec：这是一种分布式表示方法，通过神经网络将词语映射到一个低维连续向量空间（通常50-300维）。通过这种方式训练得到的词向量能够捕捉词语之间的语义关系，例如"国王 - 男人 + 女人 ≈ 女王"。这种表示方法大大降低了维度，同时保留了语义信息，是当前自然语言处理中最常用的词表示方法之一。
\end{enumerate}



\paragraph{基础 RNN} 循环神经网络，就仿照人按顺序阅读一段文字的过程来设计。它有一个隐藏状态$\vec{h}_t$，类似于人在阅读了一定文字之后，脑子里所想的东西。每读取一个字，就将这个字经过一定的规则或者神经网络，对隐藏状态进行更新：

\begin{equation}
\vec{h}_t = \tanh\rbk{\vec{b}_h + W_h \vec{h}_{t-1} + W_x \vec{x}_t}
\end{equation}

其中，$\vec{b}_h$，$W_h$以及$W_s$是权重矩阵，是神经网络的参数，需要在训练中更新的。而$\tanh$是激活函数。从这个递推式中可以清楚地看到，第 $t$ 步的隐藏状态 $\vec{h}_t$ 依赖于前一步的隐藏状态 $\vec{h}_{t-1}$，也依赖于这一步的输入 $\vec{x}_t$。

然后，对于每个隐藏状态，都可以预测此时目标序列的条件概率分布：
\begin{equation}
p(\vec{y}_t|\{\vec{x}_i\}_{i=1}^{t}) = \text{softmax} \rbk{\vec{b}_o + W_o \vec{h}_t}
\end{equation}
其中 $\vec{b}_o$ 和 $W_o$ 也是权重矩阵，即神经网络的参数。这里的输出是一个向量种类的概率分布，且仅由这一步的隐藏状态 $\vec{h}_t$ 决定。给出概率分布之后，采样即可获得具体的输出。

\paragraph{Seq2Seq} 基础 RNN 的缺点是很明显的。比如在翻译任务中，基础 RNN 要求输出和输入的序列长度相同，而且有让序列中的每个字一一对应的倾向。这明显是做不到的事情，英文文本和中文文本并不一样长，而且顺序也不一定一样。

那么 Seq2Seq 则提供了一种解决方案，它有两个 RNN。其中，第一个叫做编码器 Encoder，它把输入序列 $\fbk{\vec{x}_i}_{i=1}^{T}$ 编码成一个向量 $\vec{c}$，然后作为第二个 RNN 的输入：
\begin{equation}
    \vec{c} = \text{Encoder}\rbk{\fbk{\vec{x}_i}_{i=1}^{T}}=\vec{h}_T
\end{equation}
嗯，其实就相当于是，在读字的过程中不作输出，只更新隐藏状态。然后，用最后一个隐藏状态，相当于说：我读完整个句子了，可以开始翻译了。这个向量$\vec{c}$叫做上下文向量 (Context Vector)，我们期望它包含了整个句子的语义信息。

第二个 RNN，叫做解码器 Decoder。它接受两个输入，其中一个是来自编码器的上下文向量$\vec{c}$，另一个则是上一步输出的向量。我们设第 $t$ 步解码器的隐藏状态为 $\vec{s}_t$，已经输出了的 (上一个) 向量是 $\vec{y}_{t-1}$，那么 
\begin{equation}
    \vec{s}_t = \tanh\rbk{\vec{b} + W_s \vec{s}_{t-1} + W_y \vec{y}_{t-1} + W_c \vec{c}}
\end{equation}
其中 $\vec{b}$，$W_s$，$W_y$，$W_c$ 是权重矩阵。这种把刚刚自己输出的东西，作为下一步的输入的行为，叫做自回归 (Auto-regression)。

当然，有了隐藏状态之后，即可计算这一步的输出 (概率分布)：
\begin{equation}
    P(\vec{y}_t| \fbk{\vec{x}_i}_{i=1}^{T}, \fbk{\vec{y}_i}_{i=1}^{t-1}) = \text{softmax} \rbk{\vec{b}_o + W_o \vec{s}_t}
\end{equation}
其中 $\vec{b}_o$ 和 $W_o$ 都是 Decoder 的参数。这样，只要 Decoder 愿意，它可以自行决定该什么时候结束输出，从而更加适合翻译任务。

\paragraph{导师驱动训练} 在训练自回归模型时，一般会采用叫做导师驱动 (teacher forcing) 的策略。

直觉上，我们在训练时，给定一串输入 $\fbk{\vec{x}_t}_{t=1}^{T}$，并让 RNN 按照顺序依次给出输出 $\fbk{\hat{\vec{y}}_t}_{t=1}^{T}$。然后，将这串输出和真实值 $\fbk{\vec{y}_t^*}_{t=1}^{T}$ 做对比，计算损失：
\begin{equation}
    \mathcal{L} = -\sum_{t=1}^{T} \sum_{i=1}^{d} y_{t,i}^* \log(\hat{y}_{t,i})
\end{equation}
其中 $y_{t,i}^*$ 表示第 $t$ 步，这个字是否为词汇表中的第 $i$ 个字，如果是则为 1，否则为 0，这叫做独热 (One-hot) 编码。$d$ 表示输出向量的维度，它等于词汇表的大小。而$\hat{y}_{t,i}$ 表示第 $t$ 步，输出字应当为词汇表中第 $i$ 个字的概率。
但这样会有个问题，特别是文本输出中，如果其中一个字预测错了，那么后面的字可能就跟着全错掉了。这显然对稳定预测不利。

所以，为了降低训练难度，我们不需要 RNN 正确预测出每一个字，而只需要让它在前文正确的情况下，正确预测出下一个字即可。